package pressure

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"poker/model"
	"poker/utils"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

// HttpRequestData 表示 HTTP 请求的数据
type HttpRequestData struct {
	Method  string
	URL     string
	Headers map[string]string
	Timeout time.Duration
}

// HttpPressure 函数用于执行 HTTP 压力测试
// totalRequests: 总请求数
// duration: 测试持续时间（单位：秒）
// concurrency: 并发数
func HttpPressure(totalRequests int, duration int, concurrency int) {
	// 初始化计数器
	var successCount int64 = 0
	var failedCount int64 = 0
	var totalTime int64 = 0
	var timeoutCount int64 = 0

	// 创建 WaitGroup
	var wg sync.WaitGroup

	// 控制并发的信号量
	semaphore := make(chan struct{}, concurrency)

	// 计算每次请求的间隔时间（单位：纳秒）
	requestInterval := time.Duration(duration) * time.Second / time.Duration(totalRequests)

	// 随机生成 4 个 channel 值
	channels := []string{"channel1", "channel2", "channel3", "channel4"}

	// 创建一个本地随机数生成器
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))

	// 开始时间
	startTime := time.Now()

	// 发送请求
	for i := 0; i < totalRequests; i++ {
		wg.Add(1)
		semaphore <- struct{}{} // 获取信号量
		go func(i int) {
			defer wg.Done()
			defer func() { <-semaphore }() // 释放信号量

			// 每次请求的开始时间
			start := time.Now()

			// 随机选择一个 channel 值
			channel := channels[rng.Intn(len(channels))]

			// 示例请求数据
			request := HttpRequestData{
				Method:  "POST",
				Headers: map[string]string{"Content-Type": "application/json"},
				Timeout: 3 * time.Second,
			}
			request.URL = fmt.Sprintf("http://119.45.250.7:3000/zhenren/api/%s/upload", channel)

			// 示例用户数据，Uid 递增
			user := model.User{
				Uid: fmt.Sprintf("user%d", i+1),
			}
			// 生成 4KB 的字符串
			user.Data = generateFixedString(4*1024) + "_" + user.Uid
			user.Auth = utils.GenerateAuth(user.Uid + user.Data + channel)

			// 将 JSON 数据序列化为字节流
			jsonDataBytes, err := json.Marshal(user)
			if err != nil {
				fmt.Printf("JSON 数据序列化失败：%v\n", err)
				return
			}

			// 创建 HTTP 请求
			req, err := http.NewRequest(request.Method, request.URL, bytes.NewBuffer(jsonDataBytes))
			if err != nil {
				fmt.Printf("创建请求失败：%v\n", err)
				atomic.AddInt64(&failedCount, 1)
				return
			}

			// 设置请求头
			for key, value := range request.Headers {
				req.Header.Set(key, value)
			}

			// 设置请求超时
			client := &http.Client{Timeout: request.Timeout}
			resp, err := client.Do(req)
			duration := time.Since(start)

			if err != nil {
				if strings.Contains(err.Error(), "deadline") {
					atomic.AddInt64(&timeoutCount, 1)
				} else {
					fmt.Printf("请求失败：%v\n", err)
					atomic.AddInt64(&failedCount, 1)
				}
				return
			}
			defer resp.Body.Close()

			// 读取响应体
			_, err = io.ReadAll(resp.Body)
			if err != nil {
				fmt.Printf("读取响应体失败：%v\n", err)
				atomic.AddInt64(&failedCount, 1)
				return
			}

			atomic.AddInt64(&successCount, 1)
			atomic.AddInt64(&totalTime, int64(duration))

			// 计算本次请求的实际耗时
			actualDuration := time.Since(start)

			// 如果实际耗时小于间隔时间，则延迟剩余时间
			if actualDuration < requestInterval {
				time.Sleep(requestInterval - actualDuration)
			}
		}(i)
	}

	// 等待所有请求完成
	wg.Wait()

	// 计算总耗时
	totalTimeInSeconds := time.Since(startTime).Seconds()

	// 输出结果
	fmt.Printf("总请求数：%d\n", totalRequests)
	fmt.Printf("成功请求数：%d\n", successCount)
	fmt.Printf("失败请求数：%d\n", failedCount)
	fmt.Printf("超时请求数：%d\n", timeoutCount)
	fmt.Printf("平均响应时间：%f 秒\n", float64(totalTime)/float64(successCount)/1e9)
	fmt.Printf("总耗时：%f 秒\n", totalTimeInSeconds)
	fmt.Printf("QPS：%f\n", float64(totalRequests)/totalTimeInSeconds)
}

// generateFixedString 生成指定长度的固定字符串
func generateFixedString(length int) string {
	// 使用一个简单的重复字符来生成固定字符串
	repeatChar := "a"
	return strings.Repeat(repeatChar, length)
}
